El objetivo de este trabajo es analizar mediante una exploración de datos las características de las Ofertas Relámpago en Brasil durante el mes de junio y julio del 2021. A través de herramientas de visualización como Plotly identificaremos los patrones y tendencias subyacentes de los datos provistos.
El notebook se divide en tres partes, la primera consiste en un análisis general de las distribuciones de las variables y sus características a modo de familiarizarnos con los datos. En la segunda parte, nos enfocaremos en las cualidades de cada clase de producto y la composición de las ventas. Luego, en la tercer sección respondemos cuáles son los momentos de la semana donde se realizan mayor cantidad de compras, asimismo analizamos cual es la duración óptima de cada oferta según la clase y categoría del producto. Por último se encuentran las conclusiones del trabajo.
El dataset utilizado ofertas_relampago.csv consiste de las siguientes 13 columnas:
Importamos las librerias a usar
import pandas as pd
import numpy as np
from plotly.subplots import make_subplots
import plotly_express as px
import plotly.graph_objects as go
import plotly.figure_factory as ff
Cargamos el dataset
df= pd.read_csv('data\ofertas_relampago.csv')
df.head()
A partir del describe observamos que no hay missing values y podemos tener una noción a simple vista de la distribución de las variables.
df.shape
df.describe(include='all')
df.info()
Con el siguiente código logramos obtener un primer approach al dataset de forma de conocer la distribución de cada una de las variables. Así, logramos identificar outliers y hallar las tendencias que caracteriza a cada variable.
#iteramos para obtener el historgrama de cada variable, usando la librería plotly
for columna in df.columns:
fig = px.histogram(df, x=columna, text_auto='.2s',title=f'Histograma {columna}')
fig.update_traces(textfont_size=12, textangle=0, textposition="outside", cliponaxis=False)
fig.show()
Con el fin de validar la existencia de outliers, usamos boxplots para observar mejor las distribuciones de las variables.
for columna in list(df.columns):
fig = px.box(df, x=columna,title=f'BoxPlot {columna}')
fig.show()
OFFER_START_DATE : Las fechas donde comienzan las ofertas abarcan el período entre el 1 de junio del 2021 hasta el 31 de julio de 2021. Observamos una tendencia creciente en la cantidad de ofertas que comienzan en las dos ultimas semanas de julio mientras que sucede lo contrario para el mes de junio. Ademas, la frecuencia máxima de ofertas que comienzan en julio fue de 1.3k mientras que el valor mínimo fue de 254, para tan solo 15 dias antes.
OFFER_START_DTTM : Esta variable corresponde a la fecha y franja horaria en la cual comenzó cada oferta relámpago. Nuevamente, observamos como esta distribución es similar a la distribución multivariada de START_DATE con la única distinción de que existe una tendencia a comenzar ofertas relámpago en la tarde, entre las 12hs hasta las 23hs. Es peculiar observar como para una misma fecha la frecuencia es muy pequeña antes de las 11 am para luego aumentar de forma considerable luego de las 12hs.
OFFER_FINISH_DTTM: Esta variable explica las franjas horarias donde finalizan las ofertas. Existe una tendencia a finalizar las ofertas en la madrugda entre las 12 am y el mediodía, al contrario de la tendencia observada para el comienzo de las ofertas. Además, es evidente una distribución similar a la forma de la multivariada de START_DATE_DTTM, y es esperable ya que al ser una oferta relámpago las frecuencias de comienzo de las ofertas deben estar correlacionadas con una fecha cercana ha si.
OFFER_TYPE: Para esta variable obtenemos único valor lo cual es esperado ya que analizaremos solo las ofertas relámpago.
INVOLVED_STOCK: Esta variable explica la cantidad de stock involucrado en cada oferta, observamos que la distribución right skewed evidencia una tendencia clara a que el stock no supere las 19 unidades (con una frecuencia de 21k),es decir, en su mayoría las ofertas relámpago no superan las 20 unidades de stock a excepción de casos aislados con frecuencias mínimas tal como se observa en la gráfica Podemos inferir que el motivo detrás de estas excepciones debe ser por elección del vendedor o por el tipo de producto ofrecido y la demanda esperada para cada uno de ellos.
REMAINING_STOCK_AFTER_END: Para esta variable es de esperar que el stock restante luego de que finalice la oferta sea mínimo, pero para nuestra sorpresa encontramos valores atípicos donde la cantidad de stock restante supera las 1000 unidades. De la misma forma que sucede con INVOLVED_STOCK, observamos que en su mayoría las ofertas relámpago son un éxito de forma que el vendedor conserva entre 0 y 9 unidades al finalizar la oferta, la frecuencia para estos casos es alta, 25k, tal como se observa en la gráfica. Sin embargo, para los valores atípicos debemos considerar otros factores que logren explicar lo sucedido, desde el tipo de producto, la demanda, el stock inicial, el precio ofrecido u otros factores que pudieron haber intervenido.
SOLD_AMOUNT: Esta variable posee una distribucion right_skewed con una tendencia a vender a un monto menor a 9.99,y una media de 12.42. A la derecha del gráfico observamos como los valores disminuyen significativamente, donde la frecuencia para un monto cercano a 100 es 56. Es evidente que en este tipo de ofertas rondan los montos entre 0 y 99.99 donde los valores más frecuentes son montos menores a 40.
SOLD_QUANTITY: Esta variable indica la cantidad de productos vendidos, la frecuencia más alta la obtenemos para una unidad, seguido por compras de 2 a 3 unidades. El valor esperado es 10 aunque la media es corrida hacia la derecha por el tipo de distribución right skewed y la gran cantidad de valores atípicos mayores a 145. Asimismo, observamos que los valores atípicos reflejan casos particulares que debemos estudiar por separado donde otros factores intervienen como el tipo de producto, el mercado, la demanda y el tipo de comprador.
SHIPPING_PAYMENT__TYPE: Esta variable explica el método de entrega el cual puede tomar dos valores: free_shipping o none. Para el primer valor obtenemos una frecuencia de 27k superando por 5k a la segunda opción. Esto puede deberse a las preferencias de entrega de cada consumidor, y si decide pagar el shipping o no.
DOM_DOMAIN_AGG1: Esta variable es la clasificación por categoría de producto, donde observamos que los productos más vendidos en este tipo de ofertas es HOME & DECOR seguido por APPAREL ACCESORIES. Esta clasificación distingue los productos por categorías y permite agruparlos según cada tipo.
VERTICAL: Con esta variable logramos conocer la clase a la que pertenece cada grupo de productos, es una forma de agrupar cada dominio de modo que reducimos la cantidad de categorías logrando una agrupacion vertical. Según esta agrupación, a diferencia de la categorización de DOM_DOMAIN_AGG1 la frecuencia de la clase APP & SPORTS es mayor a la de HOME & INDUSTRY como indicaba la variable anterior. Esta agrupacián global permite identificar tendencias a nivel macro para luego conocer los detalles de cada categoria y dominio.
DOMAIN_ID: Es el nombre de cada tipo de producto, es el dominio el cual permite identificar y distinguir los productos entre sí. Para esta distribución observamos una frecuencia mayor para máscaras de cirugía o industriales lo cual tiene sentido ya que para los meses de junio y julio de 2021 en Brasil, a un año del inicio de la pandemia del COVID 19, era obligatorio el uso de tapabocas en espacios cerrados. Por ello, podemos considerar esta gran demanda por este tipo de productos, atípica ya que se debió a una causa externa, ajena a las preferencias esperadas del mercado. Asimismo, observamos que la gráfica puede ser dividida en dos partes, unas frecuencias a la derecha entre 100 y 500 unidades, entre las que encontramos: auriculares, luced led, anteojos, calzado deportivo, entre otros; y las frecuencias de la izquierda que no logran superar 50.
Para estudiar la correlación entre las variables realizaremos un Correlation Map y luego una gráfica para las variables que posean mayor correlación entre sí.
df_corr = df.corr()
x = list(df_corr.columns)
y = list(df_corr.index)
z = np.array(df_corr)
fig = ff.create_annotated_heatmap(
z,
x = x,
y = y ,
annotation_text = np.around(z, decimals=2),
colorscale='blues')
fig.update_traces(textfont_size=12)
fig.update_layout(title='Mapa de Correlación Ofertas Relámpago')
fig.show()
fig = px.scatter(df, x='REMAINING_STOCK_AFTER_END', y="INVOLVED_STOCK", title="REMAINING_STOCK_AFTER_END vs INVOLVED_STOCK corr= 0.99")
fig.show()
fig = px.scatter(df, x='SOLD_AMOUNT', y="SOLD_QUANTITY", title="SOLD_AMOUNT vs SOLD_QUANTITY corr= 0.71")
fig.show()
fig = px.scatter(df, x='INVOLVED_STOCK', y="SOLD_AMOUNT", title="INVOLVED_STOCK vs SOLD_AMOUNT corr= 0.56")
fig.show()
REMAINING_STOCK_AFTER_END vs INVOLVED_STOCK : Tal como se espera la cantidad de stock inicial influye en el remanente al finalizar la oferta, como se observa en la gráfica, la correlación entre ambas variables es muy alta siendo esta de 0.99. Esto significa que en la medida en la que aumente la cantidad de unidades iniciales en el stock mayor sera el stock remanente al finalizar. Podemos inferir que existe un número esperado de compras en el corto período de la oferta por lo que una vez alcanzado este número, todas las unidades superfluas de stock inicial no seran vendidas convirtiendose en stock remanente.
SOLD_AMOUNT vs SOLD_QUANTITY : Existe una correlación positiva del 71% entre la cantidad de stock total ventido y el monto. Es decir, cuantas mas unidades se vendan mayor sera el monto, por lo que a mayor cantidad de unidades vendidas mayor sera el ingreso.
INVOLVED_STOCK vs SOLD_AMOUNT: La cantidad de stock influye en un 56% de los casos en el monto. Podemos inferir que estas variables se comportan de forma independiente ya que el monto en pocos casos sera afectado por el stock disponible, sino que respondera a las variaciones de la oferta y la demanda.
Realizamos un scatter matrix para las variables que poseen mayor correlación entre sí y de que forma influye cada clase de productos en las mismas.
Como se observa en la gráfica debajo, encontramos que los productos pertenecientes a la clase BEAUTY AND HEALTH tienden a tomar valores más altos para todas las variables, incluso en ocasiones suelen ser los mas dispersos, como al comparar REMAINING_STOCK y SOLD_AMOUNT. Por otro lado, cuando observamos lo que sucede en la correlación entre SOLD_AMOUNT y SOLD_QUANTITY vemos que para la clase BEAUTY AND HEALTH esta correlación es positiva mientras que para la clase CE no lo es, de forma que obtenemos dos distribiciones distintas para la misma correlación según cada clase.
Esto nos demuestra la variedad de comportamientos que podemos tener para cada clase ya que cada una opera en un mercado distinto con sus propias reglas. Asimismo, es interesante observar como la clase HOME AND INDUSTRY mantiene unn rango de valores mucho menor que el resto de las clases encontrandose cerca de los ejes, esto se debe a que de este tipo de productos no suele haber tanta cantidad de ofertas, stock y por ende productos remanentes al finalizar las ofertas relámpago, a diferencia de otras clases. Además, es evidente que no todas las clases poseen la misma influencia sobre las correlaciones entre las variables ya que no aparecen todas con la misma frecuencia, incluso sucede que clases como ENTERTAINMENT no logran ser vistas en este tipo de gráficos. Por ello, en la siguiente sección analizaremos la influencia de cada clase, dominio y producto y su respectivo comportamiento.
fig = px.scatter_matrix(df, dimensions=["REMAINING_STOCK_AFTER_END", "INVOLVED_STOCK", "SOLD_AMOUNT", "SOLD_QUANTITY"], color="VERTICAL", height= 890)
fig.update_layout(title='Scatter Matrix')
fig.show()
Para esta parte del EDA realizaremos un enfoque en los dominios, categorias y clases de productos para conocer en que medida influyen en las ventas durante las ofertas relámpago
fig = px.sunburst(df, path=['VERTICAL', 'DOM_DOMAIN_AGG1'], values='SOLD_AMOUNT',
color='VERTICAL', hover_data=['VERTICAL'])
fig.update_layout(title= 'Composición de SOLD_AMOUNT por Clase y Categoría')
fig.show()
En el gráfico observamos como la clase predominante con mayor cantidad de monto de ventas es BEAUTY AND HEALTH, seguida por CE y luego HOME & INDUSTRY y APP & SPORTS. Asimismo, es interesante identificar las categorias de mayor preferencia y predisposición a participar de las ofertas relámpago, entre ellas encontramos: PHARMACEUTICS, MOBILE, ELECTRONICS, COMPUTERS, HOME&DECOR, APPAREL, SPORTS, FOOTWEAR, entre otros. Es interesante observar como se refleja el aumento de demanda por elementos farmacéuticos, entre los cuales encontramos los tapabocas. Tal como observamos en la parte anterior, el incremento de la demanda por este tipo de productos es anómala a los comportamientos esperados durante este tipo de ofertas. Sin embargo, es un reflejo de como factores externos logran alteran los patrones de compra del consumidor y en este caso la composición de las ventas. Sería interesante poder analizar esta misma composición pero para las ventas del mismo periodo durante el 2019, y observar las varicaciones en las preferencias de compra.
Por otro lado, esta composición nos permite comprender a simple vista que categorías son ofertadas con mayor frecuencia y son las elegidas por los vendedores para comercializar a través de mercado libre. A su vez, permite tener una noción de que categorías prevalecen sobre las demás y que factores influyen en que sean las más comercializadas.
Al comparar la composición de la cantidad de productos ofertados segun el dominio y cuantos de ellos se logran efectivamente vender podemos explicar porque algunos productos son ofertados con mayor frecuencia y como varía el stock remanente para cada categoría.
for variable in ['SOLD_QUANTITY', 'INVOLVED_STOCK', 'REMAINING_STOCK_AFTER_END']:
fig = px.treemap(df, path=[px.Constant('OFERTA RELAMPAGO'), 'VERTICAL', 'DOM_DOMAIN_AGG1'], values= variable,
color='VERTICAL', hover_data=['VERTICAL'])
fig.update_layout(title= f'Treemap {variable}')
fig.show()
fig = px.histogram(df, x="VERTICAL", y=["SOLD_QUANTITY", "INVOLVED_STOCK", "REMAINING_STOCK_AFTER_END"], title="Composición de stock según cada clase")
fig.show()
Los treemaps nos muestras las compisiones de stock disponibles, remanentes y vendidos para cada clase. Tal como concluimos en la primera parte, existe una correlación muy fuerte entre REMAINING_STOCK_AFTER_END y INVOLVED_STOCK, y nuevamente lo vemos en los dos treemaps ya que estos son casi idénticos en sus composiciones. Por otro lado, cuando comparamos ambos con SOLD_AMOUNT observamos que las distribuciones por clase poseen grandes diferencias. Es decir, observamos que el porcentaje de unidades vendidas en BEAUTY & HEALTH supera el porcentaje del resto de las categorías juntas.
Además, de acuerdo con lo que muestra el bar plot observamos que la categoría más vendida es la que posee mayor cantidad de stock remanente al finalizar la oferta, lo mismo sucede para las clases de HOME & INDUSTRY, APP & SPORTS y CE, donde las unidades vendidas no son ni la mitad del stock remanente. Es curioso, ya que deberíamos esperar que el stock remanente sea menor en relación con el stock vendido, aún así notamos que la demanda es sobreestimada o el stock es fijo independientemente de las ofertas que se realicen. Pero sin duda, llama la atención las proporciones y como la clase más vendida es la que refleja más este efecto, que se esperaría en productos que son vendidos con menor frecuencia. Sin embargo, debemos guiarnos por el supuesto de que la composición es independiente a las ofertas por lo que no se espera que se venda una porción grande del stock en las pocas horas que dura la misma, sino que este se planea vender en plazos de tiempo mayores.
En esta sección nos preguntamos que días de la semana y en que momento se comercilizan cada tipo de productos. Además, observamos de que manera influye la duración de las ofertas en la predisposición a comprar.
#cambiamos el tipo de datos de las columnas datetime de object a datetime, de forma que podamos realizar operaciones entre sí
df['OFFER_START_DTTM'] = pd.to_datetime(df['OFFER_START_DTTM'])
df['OFFER_FINISH_DTTM'] = pd.to_datetime(df['OFFER_FINISH_DTTM'])
#creamos una nueva columna llamada duracion que es la diferencia entre el datetime de fin de la oferta y el datetime de comienzo
df['DURACION_OFERTA'] = df['OFFER_FINISH_DTTM'] - df['OFFER_START_DTTM']
df.head()
Verificamos que todas las ofertas duren menos de 24 horas
df['days']=[str(i)[0] for i in df['DURACION_OFERTA']]
df['days'].value_counts()
De acuerdo al value_counts observamos que existe 1 oferta que supera las 24 horas, por ello buscaremos la entrada para analizar el caso atípico. Sin embargo observamos que claramente se trata de un outlier, el cual debemos considerar a la hora de sacar conclusiones, si posteriormente continuaramos con el análisis con una fase de modelado deberemos tomar medidas como reemplazar el valor por uno de tendencia central o simplemente eliminarlo de forma que no altere los resultados y patrones generales del conjunto de datos.
df[df['days']== '4']
Podemos observar que el valor atípico corresponde a una máscara para dormir, sin embargo sorprende que este dentro de una oferta relámpago ya que estas suelen durar menos de un día. Esto puede deberse a un error en el sistema o en la asignación del tipo de oferta, o incluso puede ser que efectivamente se trate de una oferta relámpago que no sigue las tendencias de la muestra. Con el objetivo de analizar las tendencias y patrones que caracterizan a las ofertas relámpago, en esta ocasión eliminaremos la entrada de forma que no altere las medidas de tendencia central. Al eliminar el dato atípico reducimos el ruido que este podría generar en el análisis, sin embargo es un caso particular cuyo motivo deberíamos averiguar.
df.drop(df[df['days']== '4'].index, inplace=True)
#convirtiendo el datetime en string podemos hacer slices de forma de obtener solo la cantidad de horas que dura cada oferta sin considerar los minutos
df['DURACION_HORAS']= [str(i)[6:9] for i in df['DURACION_OFERTA']]
df.DURACION_HORAS.value_counts()
#Graficaremos la duracion en horas de cada oferta para cada categoría, para ello utilizaremos subplots de plotly
fig = make_subplots(
rows=3, cols=3, subplot_titles=('CPG', 'CE', 'APP & SPORTS', 'T & B', 'BEAUTY & HEALTH', 'HOME & INDUSTRY', 'ENTERTAINMENT', 'ACC', 'OTHERS'))
# Agregamos los traces para cada categoría, en total son 9 bar plots en una matriz de 3x3
fig.add_trace(go.Bar(x=sorted(list(df.loc[df['VERTICAL'] == 'CPG'].DURACION_HORAS.unique())),
#usamos sorted para asegurarnos de que el orden sea el mismo para la x y la y, ademas los valores quedan en orden ascendente y es mas estético al graficar
y= list(df.loc[df['VERTICAL'] == 'CPG'].DURACION_HORAS.value_counts().sort_index())),
#de la misma forma que en la x, usamos sort_index para orden los valores en orden ascendente y asegurarnos de que sean correspondidos por la x
row=1, col=1)#determinamos el lugar del plot dentro de la matriz de 3x3 creada por los subplots
fig.add_trace(go.Bar(x=sorted(list(df.loc[df['VERTICAL'] == 'CE'].DURACION_HORAS.unique())),
y=list(df.loc[df['VERTICAL'] == 'CE'].DURACION_HORAS.value_counts().sort_index())),
row=1, col=2)
fig.add_trace(go.Bar(x=sorted(list(df.loc[df['VERTICAL'] == 'APP & SPORTS'].DURACION_HORAS.unique())),
y=list(df.loc[df['VERTICAL'] == 'APP & SPORTS'].DURACION_HORAS.value_counts().sort_index())),
row=1, col=3)
fig.add_trace(go.Bar(x=sorted(list(df.loc[df['VERTICAL'] == 'T & B'].DURACION_HORAS.unique())),
y=list(df.loc[df['VERTICAL'] == 'T & B'].DURACION_HORAS.value_counts().sort_index())),
row=2, col=1)
fig.add_trace(go.Bar(x=sorted(list(df.loc[df['VERTICAL'] == 'BEAUTY & HEALTH'].DURACION_HORAS.unique())),
y=list(df.loc[df['VERTICAL'] == 'BEAUTY & HEALTH'].DURACION_HORAS.value_counts().sort_index())),
row=2, col=2)
fig.add_trace(go.Bar(x=sorted(list(df.loc[df['VERTICAL'] == 'HOME & INDUSTRY'].DURACION_HORAS.unique())),
y=list(df.loc[df['VERTICAL'] == 'HOME & INDUSTRY'].DURACION_HORAS.value_counts().sort_index())),
row=2, col=3)
fig.add_trace(go.Bar(x=sorted(list(df.loc[df['VERTICAL'] == 'ENTERTAINMENT'].DURACION_HORAS.unique())),
y=list(df.loc[df['VERTICAL'] == 'ENTERTAINMENT'].DURACION_HORAS.value_counts().sort_index())),
row=3, col=1)
fig.add_trace(go.Bar(x=sorted(list(df.loc[df['VERTICAL'] == 'ACC'].DURACION_HORAS.unique())),
y=list(df.loc[df['VERTICAL'] == 'ACC'].DURACION_HORAS.value_counts().sort_index())),
row=3, col=2)
fig.add_trace(go.Bar(x=sorted(list(df.loc[df['VERTICAL'] == 'OTHERS'].DURACION_HORAS.unique())),
y=list(df.loc[df['VERTICAL'] == 'OTHERS'].DURACION_HORAS.value_counts().sort_index())),
row=3, col=3)
# Escribimos los titulos de la variable x
fig.update_xaxes(title_text="Duración en horas", row=1, col=1)
fig.update_xaxes(title_text="Duración en horas", row=1, col=2)
fig.update_xaxes(title_text="Duración en horas", row=1, col=3)
fig.update_xaxes(title_text="Duración en horas", row=2, col=1)
fig.update_xaxes(title_text="Duración en horas", row=2, col=2)
fig.update_xaxes(title_text="Duración en horas", row=2, col=3)
fig.update_xaxes(title_text="Duración en horas", row=3, col=1)
fig.update_xaxes(title_text="Duración en horas", row=3, col=2)
fig.update_xaxes(title_text="Duración en horas", row=3, col=3)
# Update title and height
fig.update_layout(title_text="Duración de las ofertas relámpago según clase de producto", height=900, showlegend=False)
fig.show()
Como podemos observar en la gráfica existe una tendencia general para todas las clases de producto, donde la duración de la oferta es de 6 horas aproximadamente. Por otro lado, podemos observar ciertas características propias de cada clase, por ejemplo: Para BEAUTY & HEALTH encontramos una frecuencia alta para duraciones entre 6 y 8 horas, sin embargo se observa también una frecuencia considerable para ofertas que duran menos de 1 hora, de forma análoga sucede con CE, HOME & INDUSTRY, APP & SPORTS. La pregunta es si efectivamente tienen mas éxito las ofertas que duran 6 horas o si hay otros factores como el día de la semana y el momento del día que intervienen en los resultados de ventas. Por ello, en la siguiente sección analizaremos el efecto de estas variables.
Para esta sección primero transformaremos los datos de forma de obtener una nueva variable para el dia de la semana el cual se lanzó la oferta y otra que indique el momento del día (mañana, tarde, noche) lo cual crearemos a partir de los horarios de inicio.
#transformamos la variable OFFER_START_DATE a datetime para aplicar la funcion dt.day_name() que no devuelve el nombre del día de la semana el cual se lanzó la oferta,
# el cual guardaremos en la variable WEEKDAY
df['OFFER_START_DATE'] = pd.to_datetime(df['OFFER_START_DATE'])
df['WEEKDAY']=df["OFFER_START_DATE"].dt.day_name()
#verificamos que la variable haya sido creada
df.head()
#creamos la variable start_hour a partir de un slice de OFFER_START_DTTM el cual debemos convertir antes en string para obtener solo los dos numeros que indican la hora de inicio
df['start_hour']= [str(i)[11:13] for i in df['OFFER_START_DTTM']]
b = ['00','12','20','24']
l = ['Mañana', 'Tarde', 'Noche']
df['MOMENTO_DEL_DIA_INICIO'] = pd.cut(df['start_hour'], bins=b, labels=l, include_lowest=True)
#usamos pd.cut para crear los bins de las tres categorias, asi podemos agrupar los datos y representarlos
#((el bin de la mañana comienza a las 00 ya que no encontramos ofertas que comienzen en la madrudaga y por cuestiones de simplificacion incluimos esa franja horaria))
df.info()
#verificamos que todos las entradas hayan sido asignadas a un valor de la nueva variable
#de modo que tenemos para la nueva variable la mismca cantidad de entradas que para OFFER_START_DTTM
df['MOMENTO_DEL_DIA_INICIO'].value_counts()
#Usamos plotly para realizar un bar plot para cada dia de la semana y momento, por cuestiones de escala es conveniente seleccionar de la legenda de a una variable para visualizar
fig = px.bar(df.rename(columns={'WEEKDAY':'Day', 'MOMENTO_DEL_DIA_INICIO': 'time'}),
x="VERTICAL",
y="SOLD_QUANTITY",
title="Que días de las semana y en qué momentos se vende más de cada categoría?",
barmode="group", facet_row="time", facet_col="Day",color= 'VERTICAL',
category_orders={ 'Day':['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
'time':['Mañana', 'Tarde', 'Noche']})
fig.update_layout( height=900)
fig.show()
Este gráfico es relevante en la medida en la que seleccionemos de una categoría a la vez, ya que, como habíamos concluido en la parte anterior, cada categoría posee un volumen muy distinto de ventas y de cantidad de productos ofertados con respecto a las demás. Al existir estas diferencias, por cuestiones de escalas no es posible visualizar todos a la vez. Pero, si clickeamos en cada categoría podemos observar las tendencias y volúmenes de venta para cada día de la semana y momento del día.
Para la categoría más vendida, BEAUTY AND HEALTH, observamos que los artículos cuyas ofertas comienzan en la mañana ,particularmente los jueves, miércoles y lunes, tienen mayor volumen de ventas. Mientras que, los que comienzan en la tarde comparten esta tendencia, a diferencia de que los lunes es el día con mayor cantidad de ventas. Por otro lado, observamos que luego de las 20 hs las probabilidad de una venta disminuye para esta categoría, sin embargo por la noche los días con mayor volumen de ventas son los miércoles.
Para la segunda categoría con mayor monto de ventas, CE, obtenemos que las ofertas lanzadas en la tarde de los jueves son las que obtienen mayor cantidad de compras, seguidas por las que comparten la misma franja horaria los lunes. A su vez, a diferencia de la categoría anterior, la mañana no es el momento preferido por los compradores para este tipo de productos ya que presenta un volumen mucho menor que las ofertas de la tarde. Para el horario de la noche, observamos que las compras de esta categoría son nulas, a excepción de los sábados y los lunes siendo estas cantidades son mínimas.
Para HOME & INDUSTRY, la tercera categoría con mayor volúmen de ventas, es evidente que los martes por la mañana son el día con mayor predisposición de compra de los clientes, seguido por los viernes en la mañana. A su vez, esta categoría es interesante ya que se observan compras los fines de semana tanto en la mañana como en la tarde, situación que no sucedía con las categorías anteriores. Incluso se observan compras los domingos en la noche, aunque por cantidades mínimas. Esto se debe a la naturaleza de la clase que engloba tanto herramientas, como autopartes y artículos para el hogar, que suelen ser solicitados los fines de semana.
Al observar la categoria APP & SPORTS obtenemos que las ofertas que comienzan los martes por la mañana tienen mayor cantidad de compras seguida por las que son lanzadas los días sábado. Por otro lado, en la tarde obtenemos una distribución uniforme para casi todos los días, donde el volumen de ventas se encuentra por debajo de las 150 unidades. Para la noche no se observan ofertas lanzadas que hayan tenido un volumen de compras significativo.
A partir del EDA realizado podemos concluir que el tiempo promedio de duración de las ofertas es un factor importante en el volumen de ventas, el cual difiere de acuerdo a la clase y categoría de cada producto. Para este período se observó una anomalía en las preferencias de compra esperadas del consumidor, debido a la pandemia del COVID 19 que produjo un aumento significativo en la demanda de productos farmacéuticos entre ellos y el producto mas vendido en el período: los tapabocas.
Además, observamos que la cantidad de stock remanente es mucho mayor al stock vendido y eso se debe a que la previsión de stock es para satisfacer la demanda a largo plazo y no solo la demanda esperada durante las horas de la oferta relámpago. Por otro lado, observamos como se refleja la naturaleza de cada clase de productos en los días de la semana y horas en las cuales son comercializados. En general existe mayor predisposición de compra para ofertas lanzadas durante los lunes, martes y jueves por la mañana, para la mayoría de las clases de productos. Sin embargo, cada producto responde a tendencias y patrones propios de su mercado, como por ejemplo: los artículos de tecnología son comprados en la tarde mientras que los productos de higiene personal durante la mañana.
Para concluir, logramos extraer insights significativos que identifican a las ofertas relámpago, aunque en análisis futuros sería de gran valor añadir información acerca de la ubicación de entrega del envío e información acerca de la fecha y hora de compra de cada producto asi podriamos conocer cuanto tiempo se tarda en finalizar una compra una vez iniciada la oferta.